/**
 * Copyright (c) 2009 Moogene
 * All rights reserved
 *
 * This software is the confidential and proprietary information of Moogene.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into
 * with Moogene
 */

package com.moogene.android.engine.util;

import java.util.Random;

import android.graphics.Point;

/**
 * @author Song, jiawei
 *
 */
public class MooMath {
	public static int log2(int n)
    {
        int mark, result;
        if (n >= 0x10000)
             { result = 16; mark = 0x1000000; }
        else { result = 0;  mark = 0x100; }
        if (n >= mark) { result += 8; mark <<= 4; } else mark >>= 4;
        if (n >= mark) { result += 4; mark <<= 2; } else mark >>= 2;
        if (n >= mark) { result += 2; mark <<= 1; } else mark >>= 1;
        if (n >= mark) { result += 1; }
        return result;
    }

    public static int limit(int num, int min, int max)
    {
    	// optimiz those code :
    	//
        //if (num > max)
        //    return max;
        //else if (num < min)
        //    return min;
        //else
        //    return num;
        return num > max ? max : ((num < min)? min: num);
    }

    private static Random s_rand = new Random();
    // return an integer randomly, >= min and <= max
    public static int random(int min, int max)
    {
        if (max == min)
            return min;
        else if (max < min)
        {
            int temp = min;
            min = max;
            max = temp;
        }
        //int r = Math.abs(s_rand.nextInt());
        //r %= max - min + 1;
        //r += min;
        //return r;
        return Math.abs(s_rand.nextInt()) % (max - min + 1) + min;
    }

    public static boolean randomBoolean(){
        if(random(0, 1) == 1){
            return true;
        }else{
            return false;
        }
    }

    public static int fastDistance(int x, int y)
    {
        if (x < 0) x = -x;
        if (y < 0) y = -y;
        int m = x>y ? y : x;
        return x + y - (m>>1) - (m>>2) + (m>>3);
    }

    public static int slowDistance(int dx, int dy)
    {
       int min, max;

       if ( dx < 0 ) dx = -dx;
       if ( dy < 0 ) dy = -dy;

       if ( dx < dy )
       {
          min = dx;
          max = dy;
       } else {
          min = dy;
          max = dx;
       }

       // coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min )
       return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) +
                ( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 );
    }

    public static int verySlowDistance(int dx, int dy)
    {
        if (dx < 0)
            dx = -dx;
        if (dy < 0)
            dy = -dy;

       return squareRoot((dx >> 8) * dx + (dy >> 8) * dy);
    }

    /**
     * Calculate distance of a point to a line. <br>
     * Point is (x0, y0). <br>
     * Line is linked by (x1, y1) and (x2, y2).
     * If (x1, y1) and (x2, y2) are the same point, the result is the distance between (x0, y0) and (x1, y1)
     */
    public static int distPointToLine(int x0, int y0, int x1, int y1, int x2, int y2)
    {
        // get the line formula: Ax + By + C = 0
        // this line is linked by (x1, y1) and (x2, y2)
        int A = y2 - y1;
        int B = x1 - x2;
        int C = x2*y1 - x1*y2;
        // the distance: abs(A*x0 + B*y0 + C) / sqrt(A*A + B*B)
        if (A == 0 && B == 0)
            return fastDistance(x1 - x0, y1 - y0);
        else
            return Math.abs(A*x0 + B*y0 + C) / fastDistance(A, B);
    }

    /**
     * Judge if the point(x0, y0) is between point(x1, y1) and point(x2, y2).
     */
    public static boolean isPointBetweenTwoPoints(int x0, int y0, int x1, int y1, int x2, int y2)
    {
        // get the line formula: Ax + By + C = 0
        // this line is which is perpendicular of line(x1, y1, x2, y2), over point(x0, y0)
        int A = x1 - x2;
        int B = y1 - y2;
        int C = x2*x0 - x1*x0 + y2*y0 - y1*y0;
        // the result is that the two points are on the different side of the line
        return (A*x1 + B*y1 + C > 0) ^ (A*x2 + B*y2 + C > 0);
    }

    public static boolean isLineSegmentCrossPoint(int x, int y, int x1, int y1, int x2, int y2, int distLimit)
    {
    	// If point == the line adge, it must cross.
    	if ((x == x1 && y == y1) || (x == x2 && y == y2))
		return true;

        // at first, judge whether the point is between the two extreme points of the line segment
        // get a line formula: Ax + By + C = 0
        // this line is the perpendicular to line(x1, y1, x2, y2), over point(x0, y0)
        int A = x1 - x2;
        int B = y1 - y2;
        int C = x2*x - x1*x + y2*y - y1*y;
        // if the two extreme points are on the different side of the perpendicular
        // then get the first result
        if ((A*x1 + B*y1 + C > 0) ^ (A*x2 + B*y2 + C > 0))
        {
            // the second, calculate distance of the point to the line segment
            // it should less than distance limit
            // get the line segment formula: -Bx + Ay + D = 0;
            //int D = x2*y1 - x1*y2;
            // the distance: abs(-B*x0 + A*y0 + D) / sqrt(A*A + B*B)
            return Math.abs(-B*x + A*y + x2*y1 - x1*y2) <= (distLimit * fastDistance(A, B));
        }
        else
        {
            return false;
        }
    }

    /**
     * Cacualte square root for a positive integer with 8-bits floating point
     * @param n int - Positive integer to be caculated with 8-bits floating point
     * @return int - Positive integer with 8-bits floating point
     */
    public static int squareRoot(int n)
    {
        // sqrt(0) should = 0 not throw exception.
        if (n == 0)
            return 0;

        int x = n;
        int newx = 0;
        while (true)
        {
            newx = (x + n / x * 256) >> 1;
            if ((x >= newx ? x - newx : newx - x) < 256)
                break;
            x = newx;
        }
        return x;
    }
    
    private static Point pointRotted = new Point();
    public static Point getRotPoint(Point p, Point anchor, double angrad){
    	int x = (int) ((p.x - anchor.x) * Math.cos(angrad) - (p.y - anchor.y) * Math.sin(angrad));
    	int y = (int) ((p.y - anchor.y) * Math.cos(angrad) + (p.x - anchor.x) * Math.sin(angrad));
    	pointRotted.set(anchor.x - x, anchor.y - y);
    	return pointRotted;
    }
}
